<?php declare(strict_types=1);

/**
 * @author      guosir
 * @copyright   2023-2025 owner
 **/

namespace Srv\Apps\Apis\Wallet\Ctl;

use Srv\Apps\Apis\Common\DefCtl\DefBillsBizCtl;
use Srv\Apps\Apis\User\Ctl\UserCtl;
use Srv\Apps\Proto\DTO\Wallet\CoinGiveListDTO;
use Srv\Apps\Proto\Enum\Task\TaskTypeEnum;
use Srv\Apps\Proto\Enum\YesOrNoEnum;
use Srv\Apps\Proto\VO\User\UserInfoBasicVO;
use Srv\Apps\Proto\VO\Wallet\CoinGiveListVO;
use Srv\Apps\Proto\VO\Wallet\CoinGiveVO;
use Srv\Libs\Common\CommArray;
use Srv\Libs\Common\CommJson;
use Srv\Libs\Common\CommTime;
use Srv\Libs\Frame\ControllerAbstract;
use Srv\Libs\Frame\Page;
use Srv\Libs\Storage\DataMysql;

final class CoinGiveCtl extends ControllerAbstract
{
    private ?DataMysql $DbAuto              = null;     // DB-Write

    /**
     * @return static
     * tag
     */
    final public static function tag():self
    {
        $thisObject                         = self::tagGet();
        if($thisObject instanceof self){
            $thisObject->DbAuto             = self::getDbAuto();
        }
        return $thisObject;
    }

    /**
     * @param int $cngeId
     * @return array
     * getCoinGiveSrc
     */
    public function getCoinGiveSrc(int $cngeId):array
    {
        if($cngeId < 1) return [];
        $sql    = 'SELECT cnge_id, porr_id, task_type, user_id, cnge_total_num, cnge_curr_num, cnge_use_num, cnge_start_expire, cnge_end_expire, cnge_valid_status, cnge_create_time, cnge_update_time FROM '.$this->DbAuto->getTableNameAll('coin_give').' WHERE cnge_id='.$cngeId.' AND cnge_delete=0';
        return $this->DbAuto->getDataOne($sql);
    }

    /**
     * @param Page $Page
     * @param array $whereData
     * @return CoinGiveListVO|null
     * getCoinGiveList
     */
    public function getCoinGiveList(Page $Page, array $whereData): ?CoinGiveListVO
    {
        $limitString        = $Page->getLimitString();
        $whereString        = ' WHERE cnge_delete=0 ';
        // 检索条件
        if(count($whereData) > 0)foreach ($whereData as $key => $val){
            switch ($key){
                case CoinGiveListDTO::_cngeId:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'cnge_id='. intval($val);
                    break;
                case CoinGiveListDTO::_userId:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'user_id='.intval($val);
                    break;
                case CoinGiveListDTO::_taskType:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'task_type='.intval($val);
                    break;
                case CoinGiveListDTO::_validStatus:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'cnge_valid_status='.intval($val);
                    break;
                case CoinGiveListDTO::_idNum:
                    if(strlen($val) > 10 && is_numeric($val)){
                        $whereString    .= (strlen($whereString)>0?' AND ':'').'user_id='.intval($val);
                    }else{
                        $whereString    .= (strlen($whereString)>0?' AND ':'').'user_id IN(SELECT user_id FROM '.$this->DbAuto->getTableNameAll('user_info').' WHERE usi_idnum LIKE \''.$this->DbAuto->getRealEscapeString($val).'%\' AND usi_delete=0)';
                    }
                    break;
            }
        }
        $isFail             = false;
        $sql                = 'SELECT SQL_CALC_FOUND_ROWS cnge_id, porr_id, task_type, user_id, cnge_total_num, cnge_curr_num, cnge_use_num, cnge_start_expire, cnge_end_expire, cnge_valid_status, cnge_create_time, cnge_update_time FROM '.$this->DbAuto->getTableNameAll('coin_give').$whereString.' ORDER BY cnge_id DESC '.$limitString;
        $list               = $this->DbAuto->getData($sql, $isFail);
        $totalNum           = $this->DbAuto->getDataInt('SELECT FOUND_ROWS() as num', 'num');
        if($isFail) return null;
        $CoinGiveVOList             = [];
        if(CommArray::isForeach($list)){
            $userIdList             = array_map('intval', array_column($list, 'user_id'));
            $UserInfoBasicVOList    = UserCtl::tag()->getUserInfoBasicBatch($userIdList);
            foreach($list as $item){
                $cngeIdItem         = intval($item['cnge_id']);
                if($cngeIdItem < 1) continue;
                $CoinGiveVO         = $this->getCoinGiveVO($item);
                if(!($CoinGiveVO instanceof CoinGiveVO)) continue;
                $userIdItem         = intval($item['user_id']);
                $UserInfoBasicVO    = $UserInfoBasicVOList[$userIdItem]??null;
                if($UserInfoBasicVO instanceof UserInfoBasicVO) $CoinGiveVO->setUserInfoBasic($UserInfoBasicVO);
                $CoinGiveVOList[]   = $CoinGiveVO;
            }
        }
        $CoinGiveListVO             = new CoinGiveListVO();
        $CoinGiveListVO->setList($CoinGiveVOList);
        $CoinGiveListVO->setPage($Page->getPageVO($totalNum));
        return $CoinGiveListVO;
    }

    /**
     * @param array $info
     * @return CoinGiveVO|null
     * getCoinGiveVO
     */
    public function getCoinGiveVO(array $info): ?CoinGiveVO
    {
        $cngeId             = intval($info['cnge_id']??0);
        if($cngeId < 1) return null;
        $CoinGiveVO         = new CoinGiveVO();
        $CoinGiveVO->setCngeId($cngeId);
        $CoinGiveVO->setPorrId(intval($info['porr_id']));
        $CoinGiveVO->setTaskType(TaskTypeEnum::parseValue($info['task_type']));
        $CoinGiveVO->setTotalNum(intval($info['cnge_total_num']));
        $CoinGiveVO->setCurrNum(intval($info['cnge_curr_num']));
        $CoinGiveVO->setUseNum(intval($info['cnge_use_num']));
        $CoinGiveVO->setStartExpire(intval($info['cnge_start_expire']));
        $CoinGiveVO->setEndExpire(intval($info['cnge_end_expire']));
        $CoinGiveVO->setValidStatus(YesOrNoEnum::parseValue($info['cnge_valid_status']));
        $isInvalid          = $this->checkCoinGiveValid($info)?YesOrNoEnum::YES_OR_NO_YES:YesOrNoEnum::YES_OR_NO_NO;
        $CoinGiveVO->setIsInvalid($isInvalid);
        $CoinGiveVO->setCreateTime(intval($info['cnge_create_time']));
        $CoinGiveVO->setUpdateTime(intval($info['cnge_update_time']));
        return $CoinGiveVO;
    }

    /**
     * @param int $cngeId
     * @param array $coinGiveSrc
     * @return bool
     * invalidCoinGive
     */
    public function invalidCoinGive(int $cngeId, array $coinGiveSrc):bool
    {
        if($cngeId < 1 || count($coinGiveSrc) < 1 || !isset($coinGiveSrc['cnge_id'])) return false;
        $currTime       = CommTime::getTimeStamp();
        $this->DbAuto->startTransaction();
        $sql            = 'UPDATE '.$this->DbAuto->getTableNameAll('coin_give').' SET cnge_valid_status=0, cnge_update_time='.$currTime.' WHERE cnge_id='.$cngeId.' AND cnge_delete=0 AND cnge_valid_status=1 AND cnge_curr_num>0 AND (cnge_end_expire=0 OR cnge_end_expire>'.$currTime.')';
        if($this->DbAuto->getDataNum($sql) < 1){
            $this->DbAuto->backTransaction();
            return false;
        }
        $dbbzId         = DefBillsBizCtl::tag()->getIdByKey(DefBillsBizCtl::KEY_RECHARGE_GIVE_EXPIRE);
        $optTypeNum     = 2;    // 2-支出
        $amount         = intval($coinGiveSrc['cnge_curr_num']);    // 操作数额
        $userId         = intval($coinGiveSrc['user_id']);
        $bizDataJson    = CommJson::encodeArray([
            'cngeId'        => intval($coinGiveSrc['cnge_id']),
            'userNum'       => intval($coinGiveSrc['cnge_use_num']),
            'currNum'       => intval($coinGiveSrc['cnge_curr_num']),
            'totalNum'      => intval($coinGiveSrc['cnge_total_num']),
            'expireTime'    => intval($coinGiveSrc['cnge_end_expire']),
        ]);
        $sql            = 'INSERT INTO '.$this->DbAuto->getTableNameAll('wallet_bills_record').' SET uwbr_id=0, user_id='.$userId.', dbtc_id=0, wbsr_type='.$optTypeNum.', wbsr_balance='.$amount.', wbsr_show=1, dbbz_id='.$dbbzId.', wbsr_remark_data=\''.$this->DbAuto->getRealEscapeString($bizDataJson).'\', wbsr_create_time='.$currTime;
        if($this->DbAuto->getDataId($sql) < 1){
            $this->DbAuto->backTransaction();
            return false;
        }
        $this->DbAuto->commitTransaction();
        return true;
    }

    /**
     * @param array $info
     * @return bool
     * checkCoinGiveValid
     */
    public function checkCoinGiveValid(array $info):bool
    {
        if(!isset($info['cnge_id']) || intval($info['cnge_id']) < 1) return false;
        $currNum        = intval($info['cnge_curr_num']);
        $startExpire    = intval($info['cnge_start_expire']);
        $endExpire      = intval($info['cnge_end_expire']);
        $currTime       = CommTime::getTimeStamp();
        $validStatus    = YesOrNoEnum::parseValue($info['cnge_valid_status']);
        if($validStatus !== 1) return false;
        if($endExpire !== 0 && $endExpire < $currTime) return false;
        if($currNum < 1) return false;
        return true;
    }

    /**
     * @param int $userId
     * @param int $num
     * @param int $startExpire
     * @param int $endExpire
     * @return int
     * rechargeCoinGive
     */
    public function rechargeCoinGive(int $userId, int $num, int $startExpire, int $endExpire):int
    {
        if($userId < 1 || $num < 1 || $startExpire < 0 || $endExpire < 0) return 0;
        $currTime   = CommTime::getTimeStamp();
        $sql        = 'INSERT INTO '.$this->DbAuto->getTableNameAll('coin_give').' SET user_id='.$userId.', porr_id=0, task_type=0, cnge_total_num='.$num.', cnge_curr_num='.$num.', cnge_use_num=0, cnge_start_expire='.$startExpire.', cnge_end_expire='.$endExpire.', cnge_valid_status=1, cnge_create_time='.$currTime.', cnge_update_time='.$currTime;
        $cngeId     = $this->DbAuto->getDataId($sql);
        if($cngeId < 1) return 0;
        return $cngeId;
    }
}